package com.lhd.usermanagement.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lhd.usermanagement.common.ErrorCode;
import com.lhd.usermanagement.exception.BusinessException;
import com.lhd.usermanagement.model.domain.User;
import com.lhd.usermanagement.service.UserService;
import com.lhd.usermanagement.mapper.UserMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static com.lhd.usermanagement.constant.UserConstant.USER_LOGIN_STATE;

/**
* @author lhd666
* description 针对表[user(用户)]的数据库操作Service实现
* createDate 2024-04-30 16:51:39
*/
@Service
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserMapper, User>
    implements UserService{

    @Resource
    private UserMapper userMapper;

    private static final String SALT = "lhd";

    @Override
    public long userRegister(String userAccount, String userPassword, String checkPassword, String planetCode) {
        log.info("注册功能");
        //使用 apache.commons 中 StringUtils 校验传入参数是否为空
        if (StringUtils.isAnyBlank(userAccount,userPassword,checkPassword)){
            throw new BusinessException(ErrorCode.NULL_ERROR,"参数为空");
        }
        //账户名小于4
        if (userAccount.length() < 4){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"用户账户名小于4位");
        }
        //密码长度小于8
        if (userPassword.length() < 8 || checkPassword.length() < 8){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"密码长度小于8位");
        }
        // 星球编号不能大于5
        if (planetCode.length() > 5){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"星球编号不能大于5位");
        }

        //账户不含包特殊字符
        String validPattern = "[`~!@#$%^&*()+=|{}':;',\\\\[\\\\].<>/?~！@#￥%……&*（）——+|{}【】‘；：”“’。，、？]";
        Matcher matcher = Pattern.compile(validPattern).matcher(userAccount);
        if (matcher.find()){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"账户不能包含特殊字符");
        }
        //密码和校验密码相同
        if (!userPassword.equals(checkPassword)){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"密码和校验密码相同");
        }

        //账户不能重复
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("userAccount",userAccount);
        long count = userMapper.selectCount(queryWrapper);
        if (count > 0){
            throw new BusinessException(ErrorCode.USER_ACCOUNT_EXIST);
        }

        //星球编号不能重复
        queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("planetCode",planetCode);
        count = userMapper.selectCount(queryWrapper);
        if (count > 0){
            throw new BusinessException(ErrorCode.PLANET_CODE_EXIST);
        }

        // 加密密码 为后续插入数据库做准备
        String encryptPassword = DigestUtils.md5DigestAsHex((SALT + userPassword).getBytes());
        //3. 插入数据
        User user = new User();
        user.setUserPassword(encryptPassword);
        user.setUserAccount(userAccount);
        user.setPlanetCode(planetCode);

        boolean save = this.save(user);
        if (!save){
            throw new BusinessException(ErrorCode.OPERATION_ERROR,"注册账号失败");
        }
        return user.getId();
    }


    @Override
    public User userLogin(String userAccount, String userPassword, HttpServletRequest httpServletRequest) {
        log.info("账户 = {}, 密码 = {}",userAccount, userPassword);
        //判断非空
        if (StringUtils.isAnyBlank(userAccount,userPassword)){
           throw new BusinessException(ErrorCode.NULL_ERROR,"账号 密码为空");
        }
        // 判断账户长度不小于 4 位
        if (userAccount.length() < 4){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"账号长度小于 4 位");
        }
        // 判断密码不小于 8 位
        if (userPassword.length() < 8){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"账号密码小于 8 位");
        }
        //账户不包含特殊字符
        String validPattern = "[`~!@#$%^&*()+=|{}':;',\\\\[\\\\].<>/?~！@#￥%……&*（）——+|{}【】‘；：”“’。，、？]";
        Matcher matcher = Pattern.compile(validPattern).matcher(userAccount);
        if (matcher.find()){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"账户不能包含特殊字符");
        }

        // 加密密码 并与数据库中的密码做对比
        String encryptPassword = DigestUtils.md5DigestAsHex((SALT + userPassword).getBytes());
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("userAccount",userAccount);
        queryWrapper.eq("userPassword",encryptPassword);
        User user = userMapper.selectOne(queryWrapper);

        if (user == null){
            log.info("user login failed, userAccount Cannot match userPassword");
            throw new BusinessException(ErrorCode.USER_ACCOUNT_NOT_EXIST,"用户不存在");
        }

        // 用户脱敏
        User safetyUser = getSafetyUser(user);

        // 记录用户的登录状态
        httpServletRequest.getSession().setAttribute(USER_LOGIN_STATE, safetyUser);

        //返回脱敏后的用户信息
        log.info(safetyUser.toString());
        return safetyUser;
    }

    // 用户注销
    @Override
    public int userLoginOut(HttpServletRequest request) {
        request.getSession().removeAttribute(USER_LOGIN_STATE);
        return 1;
    }

    /**
     * 脱敏用户信息
     * 该方法用于根据原始用户对象创建一个新的用户对象，其中包含的信息已经过脱敏处理。
     * 例如，电话号码和电子邮件等敏感信息可能会被替换或隐藏，以保护用户隐私。
     *
     * @param origiUser 原始用户对象，包含完整的用户信息。
     * @return 返回一个脱敏后的用户对象，其中敏感信息已被处理。
     */
    @Override
    public User getSafetyUser(User origiUser){
        if (origiUser == null){
            return null;
        }
        User safetyUser = new User();  // 创建一个新的用户对象，用于存储脱敏后的信息
        // 下面的代码用于将原始用户对象中的非敏感信息复制到脱敏后的用户对象中
        safetyUser.setId(origiUser.getId());
        safetyUser.setUsername(origiUser.getUsername());
        safetyUser.setUserAccount(origiUser.getUserAccount());
        safetyUser.setAvatarUrl(origiUser.getAvatarUrl());
        // 由于电话和电子邮件是敏感信息，在这里进行处理以保护隐私
        // 例如，可以将电话号码的中间几位用星号替换，电子邮件可以替换为邮箱的前缀加"***"。
        safetyUser.setPhone(origiUser.getPhone());
        safetyUser.setPlanetCode(origiUser.getPlanetCode());
        safetyUser.setEmail(origiUser.getEmail());
        safetyUser.setUserRole(origiUser.getUserRole());
        safetyUser.setUserStatus(origiUser.getUserStatus());
        safetyUser.setCreateTime(origiUser.getCreateTime());
        safetyUser.setIsDelete(origiUser.getIsDelete());
        return safetyUser;
    }

}




